#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json

from clickhouse import log
from clickhouse.client.clickhouse_client import ClickHouseClient
from clickhouse.common.clickhouse_constants import CommandReturnCode, ErrorCode, ListAppV2QueryConstant, \
    KerberosConstant
from clickhouse.common.parse_param import JsonParam
from clickhouse.schemas.clickhouse_schemas import CommonBodyResponse, QueryClusterResponse, Node, ListAppV2Response, \
    Resource
from common.common import output_result_file
from common.parse_parafile import ParamFileUtil


class ClickHouseResourceService:
    """
    功能描述：clickhouse资源管理服务
    """

    @staticmethod
    def check_application(pid):
        """
        功能描述：检查连通性，执行查询版本命令
        参数：从Agent框架读数据
        返回值：向Agent框架写数据
        """
        response = CommonBodyResponse()
        client = None
        try:
            file_content = JsonParam.parse_param_with_jsonschema(pid)
            app_extend_info = file_content['application']['extendInfo']
            auth_extend_info = file_content['application']['auth']['extendInfo']
            client = ClickHouseClient(pid, app_extend_info, 'application_auth', auth_extend_info)
            client.query_system_version()
        except Exception as e:
            log.error(e, exc_info=True)
            if str(e) == KerberosConstant.KINIT_FAILED.value:
                response.code = CommandReturnCode.KERBEROS_ERROR.value
                response.body_err = CommandReturnCode.KERBEROS_ERROR.value
            else:
                response.code = CommandReturnCode.INTERNAL_ERROR.value
                response.body_err = ErrorCode.ERROR_NETWORK_CONNECT_TIMEOUT.value
        finally:
            output_result_file(pid, response.dict(by_alias=True))
            if client is not None:
                client.remove_kerberos_files()

    @staticmethod
    def query_cluster(pid):
        """
        功能描述：查询集群
        参数：从Agent框架读数据
        返回值：向Agent框架写数据
        """
        response = QueryClusterResponse()
        client = None
        try:
            file_content = JsonParam.parse_param_with_jsonschema(pid)
            app_extend_info = file_content['application']['extendInfo']
            auth_extend_info = file_content['application']['auth']['extendInfo']
            client = ClickHouseClient(pid, app_extend_info, 'application_auth', auth_extend_info)
            clusters = client.query_system_clusters()
            nodes = []
            for cluster in clusters:
                node = Node()
                node.extend_info = cluster
                nodes.append(node)
            response.nodes = nodes
            output_result_file(pid, response.dict(by_alias=True))
        except Exception as e:
            log.error(e, exc_info=True)
            raise e
        finally:
            if client is not None:
                client.remove_kerberos_files()

    @staticmethod
    def list_application_v2(pid):
        """
        功能描述：查询应用详情：可查询版本、数据库列表、指定库下所有表
        参数：从Agent框架读数据
        返回值：向Agent框架写数据
        """
        response = ListAppV2Response()
        client = None
        try:
            file_content = JsonParam.parse_param_with_jsonschema(pid)
            applications = file_content['applications']
            if len(applications) != 1:
                raise Exception(f'application param error')
            app_extend_info = applications[0]['extendInfo']
            auth_extend_info = applications[0]['auth']['extendInfo']
            client = ClickHouseClient(pid, app_extend_info, 'applications_0_auth', auth_extend_info)
            query_type = app_extend_info.get('queryType', None)
            query_db_name = app_extend_info.get('queryDatabase', None)
            if query_type == ListAppV2QueryConstant.VERSION.value:
                resource = Resource()
                version = client.query_system_version()
                resource.extend_info = {"version": version}
                response.resource_list.append(resource)
                response.total = len(response.resource_list)
            elif query_type == ListAppV2QueryConstant.DATABASE.value:
                resources = ClickHouseResourceService.query_database(client)
                response.resource_list = resources
                response.total = len(response.resource_list)
            elif query_type == ListAppV2QueryConstant.TABLE.value and query_db_name is not None:
                response = ClickHouseResourceService.query_table_resource(client, query_db_name,
                                                                          file_content['condition'])
            else:
                raise Exception(f'query conditions params error')
        except Exception as e:
            log.error(e, exc_info=True)
            response.total = CommandReturnCode.ERROR.value
        finally:
            output_result_file(pid, response.dict(by_alias=True))
            if client is not None:
                client.remove_kerberos_files()

    @staticmethod
    def query_database(client):
        """
        功能描述：查询数据库
        参数：无
        返回值：数据库列表
        """
        resources = []
        databases = client.query_allow_backup_databases()
        for database in databases:
            resource = Resource()
            resource.extend_info = {
                "db_name": database.name,
                "db_engine": database.engine
            }
            resources.append(resource)
        return resources

    @staticmethod
    def query_table(client, query_db_name, condition=None):
        """
        功能描述：查询数据库下的表
        参数：数据库名称
        返回值：数据表列表
        """
        resources = []
        tables = client.query_allow_backup_tables(query_db_name, None, condition)
        replicas = client.query_system_replicas(query_db_name, None, condition)
        for table in tables:
            replica_name = ""
            for replica in replicas:
                if replica.table == table.name:
                    replica_name = replica.replica_name
                    break
            resource = Resource()
            resource.name = table.name
            resource.extend_info = {
                "table_engine": table.engine,
                "replica_name": replica_name
            }
            resources.append(resource)
        return resources

    @staticmethod
    def query_table_resource(client, query_db_name, condition=None):
        """
        功能描述：查询数据库下的表
        参数：数据库名称
        返回值：数据表列表
        """
        response = ListAppV2Response()
        response.total = client.query_allow_backup_tables_count(query_db_name)
        tables = client.query_allow_backup_tables(query_db_name, None, condition)
        replicas = client.query_system_replicas(query_db_name, None, condition)
        resources = []
        for table in tables:
            replica_name = ""
            for replica in replicas:
                if replica.table == table.name:
                    replica_name = replica.replica_name
                    break
            resource = Resource()
            resource.name = table.name
            resource.extend_info = {
                "table_engine": table.engine,
                "replica_name": replica_name
            }
            resources.append(resource)
        response.resource_list = resources
        return response
